/*    file: RtmpWriter.cpp
 *    desc:
 * 
 * created: 2017-01-04
 *  author: chuanjiang.zh@qq.com
 * company: 
 */

#include "RtmpWriter.h"
#include "TStringCast.h"
#include <algorithm>


namespace av
{

RtmpWriter::RtmpWriter():
	m_fmtCtx(),
	m_videoIndex(-1),
	m_audioIndex(-1),
	m_filename(),
	m_format()
{

}

RtmpWriter::~RtmpWriter()
{
	close();
}

bool RtmpWriter::open(const std::string& url, MediaFormat& fmt)
{
	if (url.empty())
	{
		return false;
	}

	if (!fmt.isValid())
	{
		return false;
	}

	m_format = fmt;
	m_filename = url;

	int rc = avformat_alloc_output_context2(&m_fmtCtx, NULL, "flv", m_filename.c_str());
	if (rc < 0)
	{
		return false;
	}

	/// video
	AVCodecID codecID = (AVCodecID)fmt.m_codec;
	AVCodec* codec = avcodec_find_decoder(codecID);
	if (codec != NULL)
	{
		AVStream *out_stream = avformat_new_stream(m_fmtCtx, NULL);
		AVCodecContext * codecCtx = out_stream->codec;

		avcodec_get_context_defaults3(codecCtx, codec);

		out_stream->time_base = av_make_q(1, 1000);

		codecCtx->width = m_format.m_width;
		codecCtx->height = m_format.m_height;
		codecCtx->profile = m_format.m_profile;

		if (m_format.m_bitrate > 0)
		{
			codecCtx->bit_rate = m_format.m_bitrate;
		}

		codecCtx->time_base = av_make_q(1, 1000);

		codecCtx->extradata_size = m_format.m_videoProp.size();
		codecCtx->extradata = (uint8_t*)av_memdup(m_format.m_videoProp.data(), m_format.m_videoProp.size());

		if (m_fmtCtx->oformat->flags & AVFMT_GLOBALHEADER)
		{
			out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
		}

		m_videoIndex = 0;
	}

	rc = avio_open(&m_fmtCtx->pb, m_filename.c_str(), AVIO_FLAG_WRITE);
	if (rc < 0)
	{
		close();
		return false;
	}

	rc = avformat_write_header(m_fmtCtx, NULL);
	if (rc < 0)
	{
		return false;
	}

	return true;
}

void RtmpWriter::close()
{
	if (m_fmtCtx)
	{
		if (m_fmtCtx->pb)
		{
			av_write_trailer(m_fmtCtx);

			avio_close(m_fmtCtx->pb);
		}

		avformat_free_context(m_fmtCtx);
		m_fmtCtx = NULL;

		m_filename.clear();
		m_videoIndex = -1;
		m_audioIndex = -1;
	}
}

bool RtmpWriter::isOpen()
{
	return (m_fmtCtx != NULL);
}

bool RtmpWriter::write(AVPacket& pkt)
{
	if (!isOpen())
	{
		return false;
	}

	//static int frame_index = 0;

	//int size = std::min(pkt.size, 8);
	//std::string head = comn::StringCast::toHexGroupString(pkt.data, size);

	//size = std::min(pkt.size - 8, 8);
	//std::string tail = comn::StringCast::toHexGroupString(pkt.data + pkt.size - size, size);

	//printf("%8d frames. size:%d, head:%s, tail:%s\n",
	//	frame_index, pkt.size, head.c_str(), tail.c_str());

	//frame_index ++;

	int rc = av_interleaved_write_frame(m_fmtCtx, &pkt);
	return (rc == 0);
}


}



